﻿using RockBus.Logging.Interfaces;
using RockBus.ServiceModel;
using System;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;

namespace RockBus.Hosting
{
    public abstract class RockBusServiceHost : ServiceHost
    {
        protected RockBusServiceHost(ILogger logger)
            : base()
        {
            this.Logger = logger;
        }

        protected RockBusServiceHost(ILogger logger, Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
            this.Logger = logger;
        }

        protected ILogger Logger { get; private set; }

        private bool _wasOpened;

        protected override void OnOpening()
        {
            this._wasOpened = true;
            this.Logger.LogDebug(MethodBase.GetCurrentMethod(), "Ensuring queue availability and opening ServiceHost.");
            this.EnsureQueuesAvailable();
            base.OnOpening();
        }

        protected override void OnOpened()
        {
            base.OnOpened();
            this.LogHostDetails("Opened ServiceHost on the following endpoints:");
        }

        protected override void OnClosing()
        {
            // Prevent logging if we are creating the ServiceHost only to determine the address
            if (this._wasOpened)
            {
                this.LogHostDetails("Closing ServiceHost on the following endpoints:");
            }

            base.OnClosing();
        }

        protected virtual void LogHostDetails(string description)
        {
            var sb = new StringBuilder(string.Format("Service: {0}. ", this.Description.Name));
            sb.AppendLine(description);

            foreach (ServiceEndpoint se in this.Description.Endpoints)
            {
                sb.AppendFormat("{0}, {1}, {2}",
                    se.Contract.ContractType.Name,
                    se.Binding.Name,
                    se.Address.Uri.ToString());
                sb.AppendLine();
            }

            this.Logger.LogInfo(MethodBase.GetCurrentMethod(), sb.ToString());
        }
    }

    public static class ServiceDescriptionExtensions
    {
        public static void ClearStaticEndpoints(this ServiceDescription serviceDescription)
        {
            // Remove all endpoints that serve as static endpoint
            //  (which is those endpoints that have a valid address)
            foreach (var serviceEndpoint in serviceDescription.Endpoints.ToArray())
            {
                if (!serviceEndpoint.EndpointBehaviors.Any((eb) => eb.GetType() == typeof(DynamicServiceEndpointBehavior)))
                {
                    // Remove it if it doesn't have the DynamicServiceEndpointBehavior specified.
                    serviceDescription.Endpoints.Remove(serviceEndpoint);
                }
            }
        }

        public static void ClearDynamicEndpoints(this ServiceDescription serviceDescription)
        {
            if (serviceDescription == null)
            {
                return;
            }

            // Remove all endpoints that serve as dynamic endpoint templates
            //  (which is those endpoints that have the DynamicServiceEndpointBehavior specified)
            foreach (var serviceEndpoint in serviceDescription.Endpoints.ToArray())
            {
                if (serviceEndpoint.EndpointBehaviors.Any((eb) => eb.GetType() == typeof(DynamicServiceEndpointBehavior)))
                {
                    // Remove it if it does have the DynamicServiceEndpointBehavior specified.
                    serviceDescription.Endpoints.Remove(serviceEndpoint);
                }
            }
        }
    }
}